#include "page_custom.h"
#include "SHT30.h"
#include "stdio.h"
#include "main.h"
#include "tim.h"

extern float temperature, humidity;
extern SHT30_HandleTypeDef sht30;
extern u8g2_t u8g2;

uint8_t custom_run_time;//自定义运行时间
uint32_t previousTick = 0;
uint32_t previousTickPID = 0;
uint8_t iswork_flag = 1; //工作 暂停

uint8_t hot_time = 1; //加热间隔 秒

float pid_ouput = 0; //PID运算结果

enum {
  CUSTOM_TIME,  //自定义工作时间
  CUSTOM_TEMP,  //自定义工作温度
  CUSTOM_P,  //P
  CUSTOM_I,  //I
  CUSTOM_D,  //D
  CUSTOM_FNA_SW,  //风扇开关
  CUSTOM_NUM //自定义参数数量
};

uint8_t custom_ui_param[CUSTOM_NUM]= {15,50,25,2,0,0};

M_SELECT custom_menu[8] = {
  {"[ Custom ]"},
  {"~ Set Time"},//设置时间
  {"~ Set Temp"},//设置温度
  {"~ Set P"},//设置P
  {"~ Set I"},//设置I
  {"~ Set D"},//设置D
  {"+ FAN MANUL"},
  {"- Start"},//开始
};

struct {
  float y;
  float y_trg;
} show_custom_data;//显示数据页面的动画，从底部到顶部动画

// PID参数 位置式
//typedef struct {
//    float Kp;
//    float Ki;
//    float Kd;
//    float integral;
//    float prev_error;
//} PID_Controller;

//PID_Controller pid = {20.0, 0, 0, 0.0, 0.0};


// PID 增量式
#define PID_FORCE 1

typedef struct {
  float Kp;                // 比例系数
  float Ki;                // 积分系数
  float Kd;                // 微分系数
  float error_prev;        // 上一次误差 (e_{k-1})
  float error_prev_prev;   // 上上一次误差 (e_{k-2})
  float output;            // 当前输出值（PWM占空比）
  float output_min;        // 输出下限（如 0%）
  float output_max;        // 输出上限（如 100%）
} PID_IncTypeDef;

PID_IncTypeDef pid;

void PID_Init(PID_IncTypeDef *pid, float Kp, float Ki, float Kd, float min, float max)
{
  pid->Kp = Kp;
  pid->Ki = Ki;
  pid->Kd = Kd;
  pid->error_prev = 0.0f;
  pid->error_prev_prev = 0.0f;
  pid->output = 0.0f;
  pid->output_min = min;
  pid->output_max = max;
}

float PID_Compute(PID_IncTypeDef *pid, float setpoint, float input)
{
  // 计算当前误差
  float error = setpoint - input;

  // 增量式 PID 公式: ΔU = Kp*(e_k - e_{k-1}) + Ki*e_k + Kd*(e_k - 2e_{k-1} + e_{k-2})
  float delta = pid->Kp * (error - pid->error_prev)
                + pid->Ki * error
                + pid->Kd * (error - 2 * pid->error_prev + pid->error_prev_prev);

  // 累加增量到输出
  pid->output += delta;

  // 限制输出范围
  if (pid->output > pid->output_max) {
    pid->output = pid->output_max;
  } else if (pid->output < pid->output_min) {
    pid->output = pid->output_min;
  }

  // 更新误差历史
  pid->error_prev_prev = pid->error_prev;
  pid->error_prev = error;

  return pid->output; // 返回当前PWM占空比
}

volatile uint32_t pwm_phase = 0;
volatile uint32_t pwm_duty = 0;
volatile uint8_t flag_all_power = 0;

// 把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))
// 把一个地址转换成一个指针
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))

// 把位带别名区地址转换成指针
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))

// GPIO ODR 和 IDR 寄存器地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C

#define GPIOA_IDR_Addr    (GPIOA_BASE+8)  //0x40010808
#define GPIOB_IDR_Addr    (GPIOB_BASE+8)  //0x40010C08
#define GPIOC_IDR_Addr    (GPIOC_BASE+8)  //0x40011008
#define GPIOD_IDR_Addr    (GPIOD_BASE+8)  //0x40011408
#define GPIOE_IDR_Addr    (GPIOE_BASE+8)  //0x40011808
#define GPIOF_IDR_Addr    (GPIOF_BASE+8)  //0x40011A08
#define GPIOG_IDR_Addr    (GPIOG_BASE+8)  //0x40011E08

// 单独操作 GPIO的某一个IO口，n(0,1,2...15),n表示具体是哪一个IO口
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

//1ms一次进入中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim->Instance == TIM3) {
    if(flag_all_power) {
      PAout(4) = 1;
    } else {
      pwm_phase = (pwm_phase + 1) % 1000;

      // 边界条件处理
      if(pwm_duty == 0) {
        PAout(4) = 0;
        //HAL_GPIO_WritePin(HEAT_GPIO_Port, HEAT_Pin, GPIO_PIN_RESET);
        return;
      } else if(pwm_duty >= 1000) {
        PAout(4) = 1;
        //HAL_GPIO_WritePin(HEAT_GPIO_Port, HEAT_Pin, GPIO_PIN_SET);
        return;
      }

      // 正常PWM操作
      if(pwm_phase == 0) {
        PAout(4) = 1;
        //HAL_GPIO_WritePin(HEAT_GPIO_Port, HEAT_Pin, GPIO_PIN_SET);
      } else if(pwm_phase == pwm_duty) {
        PAout(4) = 0;
        //HAL_GPIO_WritePin(HEAT_GPIO_Port, HEAT_Pin, GPIO_PIN_RESET);
      }
    }

  }
}


// PWM输出控制函数
//void PWM_Output(float duty) {
//    // 限制占空比范围
//    if(duty<=0){
//      pwm_duty = 0;
//    }else if(duty >= 100){
//      pwm_duty = 1000;
//    }else{
//      duty = duty*10.0;
//      pwm_duty = duty;
//    }
//}

// PID计算函数（保持原样）
//float PID_Calculate(float setpoint, float input) {
//    float error = setpoint - input;
//
//    pid.integral += error;
//    if (pid.integral > 100) pid.integral = 100;
//    if (pid.integral < -100) pid.integral = -100;
//
//    float output = pid.Kp * error +
//                   pid.Ki * pid.integral +
//                   pid.Kd * (error - pid.prev_error);
//    pid.prev_error = error;
//
//    return output;
//}


// 页初始化
void custom_param_init(void)
{
  PID_Init(&pid, custom_ui_param[CUSTOM_P]* 0.1f, custom_ui_param[CUSTOM_I] * 0.01f, custom_ui_param[CUSTOM_D]*PID_FORCE, 0.0f, 100.0f);
  custom_run_time=0;
  check_box_v_init(custom_ui_param);
  check_box_m_init(custom_ui_param);
}

// 页初始化
void custom_show_init(void)
{
  show_custom_data.y = 64;
  show_custom_data.y_trg = 0;
}

void confirm_COSTUM_callback(int par)
{
  if(par) {

  }
}

void custom_show(void)
{
  pid.Kp = custom_ui_param[CUSTOM_P] * 0.1f;
  pid.Ki = custom_ui_param[CUSTOM_I] * 0.01f;
  pid.Kd = custom_ui_param[CUSTOM_D] * 0.1f;
  //动画计算
  animation(&show_custom_data.y, &show_custom_data.y_trg, WIN_ANI);

  //绘制界面
  u8g2_SetDrawColor(&u8g2, 1);

  u8g2_DrawRFrame(&u8g2, 0, (int16_t)show_custom_data.y, DISP_W, 18, 2);	// 绘制外框描边
  //u8g2_DrawLine(&u8g2, DISP_W/2, (int16_t)show_custom_data.y, DISP_W/2, (int16_t)show_custom_data.y+17);	// 绘制外框描边

  u8g2_SetFont(&u8g2, LIST_FONT);

  if(iswork_flag)
    u8g2_DrawStr(&u8g2, 0+2, (int16_t)show_custom_data.y + 13, "STATE:  WORKING");
  else
    u8g2_DrawStr(&u8g2, 0+2, (int16_t)show_custom_data.y + 13, "STATE:  PAUSE");

  char buffer[30];

  snprintf(buffer, sizeof(buffer), "SET_TIME:%d min", custom_ui_param[CUSTOM_TIME]);
  u8g2_DrawStr(&u8g2, 2, 30, buffer);

  snprintf(buffer, sizeof(buffer), "T:%.2f H:%.2f %%", temperature,humidity);
  u8g2_DrawStr(&u8g2, 2, 41, buffer);

  //snprintf(buffer, sizeof(buffer), "NOW_TIME:%d min %d s", custom_run_time/60,custom_run_time%60);
  snprintf(buffer, sizeof(buffer), "P:%0.1f I:%0.2f D:%0.1f", pid.Kp,pid.Ki,pid.Kd);
  u8g2_DrawStr(&u8g2, 2, 52, buffer);

  //snprintf(buffer, sizeof(buffer), "PID:%d", pwm_duty);
  snprintf(buffer, sizeof(buffer), "%.2f %d %d", pid.error_prev,pwm_duty,custom_ui_param[CUSTOM_TEMP]);
  u8g2_DrawStr(&u8g2, 2, 63, buffer);

  //运行时间更新
  uint32_t currentTick = HAL_GetTick();
  if (currentTick - previousTick >= 1000) {  // 判断是否过去了1秒（假设HAL_GetTick()单位为毫秒）
    if(iswork_flag) {
      custom_run_time++;
    }
    previousTick = currentTick;
  }

  //温度更新
  if (currentTick - previousTickPID >= 500) {
    SHT30_GetTempAndHumidity(&sht30, &temperature, &humidity);
    if(iswork_flag) {
      if(temperature<30) {
        flag_all_power = 1;
        pid.output = 10;
      } else {
        flag_all_power = 0;
        pwm_duty = 10.0 * PID_Compute(&pid, custom_ui_param[CUSTOM_TEMP], temperature);
      }


    }
    // 执行每秒一次的操作
    previousTickPID = currentTick;
  }

  if(custom_run_time>=custom_ui_param[CUSTOM_TIME]*60) {
    iswork_flag = 0;
  }

  if(iswork_flag) {
    HAL_GPIO_WritePin(FAN_GPIO_Port,FAN_Pin,1);
    HAL_TIM_Base_Start_IT(&htim3);
  } else { //暂停则关闭风扇和加热
    HAL_TIM_Base_Stop_IT(&htim3);
    HAL_GPIO_WritePin(FAN_GPIO_Port,FAN_Pin,0);
    HAL_GPIO_WritePin(HEAT_GPIO_Port,HEAT_Pin,0);
  }
}

//显示数据页面处理过程
void custom_show_proc(void)
{
  //绘制动画
  custom_show();

  //按键处理
  if (btn.pressed) {
    btn.pressed = false;
    switch (btn.id) {
    case BTN_ID_CW:
      iswork_flag=!iswork_flag;
      break;//编码动作，执行列表滚动
    case BTN_ID_CC:
      iswork_flag=!iswork_flag;
      //list_rotate_switch();
      break;
    case BTN_ID_SP://短按或长按，退出
    case BTN_ID_LP:
      if(!iswork_flag) {
        ui.index = M_CUSTOM; //在数据展示页面里，长按一下，退出到M_CUSTOM这个菜单页面
        ui.state = S_LAYER_OUT;
      }
      break;
    }
  }
}

//自定义列表处理
void custom_proc(void)
{
  list_show(custom_menu, M_CUSTOM);

  if (btn.pressed) {
    btn.pressed = false;
    switch (btn.id) {
    case BTN_ID_CW:
    case BTN_ID_CC:
      list_rotate_switch();
      break;
    case BTN_ID_LP:
      ui.select[ui.layer] = 0;
    case BTN_ID_SP: {
      switch (ui.select[ui.layer]) {
      case 0:
        ui.index = M_MAIN;
        ui.state = S_LAYER_OUT;
        break;
      case 1:
        //弹出窗口，参数初始化：	标题，参数名，参数值，最大值，最小值，步长，背景列表名，背景列表标签
        window_value_init("Time", 0, &custom_ui_param[CUSTOM_TIME], 30,  5,  1, custom_menu, M_CUSTOM);
        break;
      case 2:
        window_value_init("Temp", 0, &custom_ui_param[CUSTOM_TEMP], 100,  0,  1, custom_menu, M_CUSTOM);
        break;
      case 3:
        window_value_init("P", 0, &custom_ui_param[CUSTOM_P], 200,  0,  1, custom_menu, M_CUSTOM);

        break;
      case 4:
        window_value_init("I", 0, &custom_ui_param[CUSTOM_I], 200,  0,  1, custom_menu, M_CUSTOM);

        break;
      case 5:
        window_value_init("D", 0, &custom_ui_param[CUSTOM_D], 200,  0,  1, custom_menu, M_CUSTOM);

        break;
      case 6:
        check_box_m_select(CUSTOM_FNA_SW);
        if(custom_ui_param[CUSTOM_FNA_SW]) {
          HAL_GPIO_WritePin(FAN_GPIO_Port,FAN_Pin,1);
        } else {
          HAL_GPIO_WritePin(FAN_GPIO_Port,FAN_Pin,0);
        }
        break;
      case 7:
        ui.index = M_CUSTOM_SHOW;
        ui.state = S_LAYER_IN;
        break;
      }
    };
    break;
    }
  }
}